//call
Function.prototype.myCall = function (obj = window, ...args) {
    const fn = Symbol("fn");
    obj[fn] = this;
    obj[fn](...args);
    delete obj[fn];
};

//apply
Function.prototype.myApply = function (obj = window, args) {
    const fn = Symbol("fn");
    obj[fn] = this;
    obj[fn](...args);
    delete obj[fn];
};

//bind
Function.prototype.myBind = function (obj = window, ...args) {
    const self = this;
    const fn = function (...rest) {
        return self.apply(this instanceof self ? this : obj, [...args, ...rest]);
    };
    fn.prototype = Object.create(self.prototype);
    return fn;
};

//debounce
function debounce(fn, wait) {
    let timer = null;
    return function () {
        clearTimeout(timer);
        timer = setTimeout(() => {
            fn.apply(this, [...arguments]);
        }, wait);
    };
}

//throttle
function throttle(fn, wait) {
    let timer = null;
    return function () {
        if (!timer) {
            timer = setTimeout(() => {
                fn.apply(this, [...arguments]);
                timer = null;
            }, wait);
        }
    };
}

//new
function myNew(Func, ...rest) {
    const obj = Object.create(Func.prototype);
    const result = Func.apply(obj, rest);
    return typeof result === "object" ? result : obj;
}

//deepclone
function deepclone(obj) {
    if (obj === null || typeof obj !== "object") return obj;

    let newObj = Array.isArray(obj) ? [] : {};

    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = typeof obj[key] === "object" ? deepclone(obj[key]) : obj[key];
        }
    }

    return newObj;
}

//promise

//array to tree
